import * as crypto from 'crypto';
import * as bcrypt from 'bcryptjs';
import { Request } from 'express';

/**
 * 安全工具类
 * 提供加密、解密、哈希、签名等安全相关功能
 */
export default class SecurityUtil {
  /**
   * 获取bcrypt哈希值
   * @param password 密码
   * @returns 哈希字符串
   */
  public static encryptPassword(password: string): string {
    return bcrypt.hashSync(password, 10);
  }

  /**
   * 验证密码是否正确
   * @param plainPassword 明文密码
   * @param encryptedPassword 加密后的密码
   * @returns 是否匹配
   */
  public static matchesPassword(plainPassword: string, encryptedPassword: string): boolean {
    return bcrypt.compareSync(plainPassword, encryptedPassword);
  }

  /**
   * 判断是否为管理员
   * @param userId 用户ID
   * @returns 是否为管理员
   */
  public static isAdmin(userId: number): boolean {
    return userId !== null && userId !== undefined && userId === 1;
  }

  /**
   * 获取用户ID (从请求对象中)
   * @param req 请求对象
   * @returns 用户ID
   */
  public static getUserId(req: Request): number {
    const user = (req as any).user;
    if (!user) {
      throw new Error('获取用户ID异常');
    }
    return user.userId;
  }

  /**
   * 获取用户名 (从请求对象中)
   * @param req 请求对象
   * @returns 用户名
   */
  public static getUsername(req: Request): string {
    const user = (req as any).user;
    if (!user) {
      throw new Error('获取用户名异常');
    }
    return user.userName;
  }

  /**
   * 获取部门ID (从请求对象中)
   * @param req 请求对象
   * @returns 部门ID
   */
  public static getDeptId(req: Request): number {
    const user = (req as any).user;
    if (!user) {
      throw new Error('获取部门ID异常');
    }
    return user.deptId;
  }

  /**
   * MD5加密
   * @param str 待加密字符串
   * @returns 加密后的字符串
   */
  public static md5(str: string): string {
    return crypto.createHash('md5').update(str).digest('hex');
  }

  /**
   * SHA1加密
   * @param str 待加密字符串
   * @returns 加密后的字符串
   */
  public static sha1(str: string): string {
    return crypto.createHash('sha1').update(str).digest('hex');
  }

  /**
   * SHA256加密
   * @param str 待加密字符串
   * @returns 加密后的字符串
   */
  public static sha256(str: string): string {
    return crypto.createHash('sha256').update(str).digest('hex');
  }

  /**
   * AES加密
   * @param data 待加密数据
   * @param key 密钥(16、24、32字节长度)
   * @param iv 初始化向量(16字节长度)
   * @returns 加密后的base64字符串
   */
  public static aesEncrypt(data: string, key: string, iv: string): string {
    // 确保key和iv的长度符合要求
    const keyBuffer = Buffer.from(key.padEnd(32).slice(0, 32));
    const ivBuffer = Buffer.from(iv.padEnd(16).slice(0, 16));

    const cipher = crypto.createCipheriv('aes-256-cbc', keyBuffer, ivBuffer);
    let encrypted = cipher.update(data, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
  }

  /**
   * AES解密
   * @param data 待解密数据(base64格式)
   * @param key 密钥(16、24、32字节长度)
   * @param iv 初始化向量(16字节长度)
   * @returns 解密后的字符串
   */
  public static aesDecrypt(data: string, key: string, iv: string): string {
    // 确保key和iv的长度符合要求
    const keyBuffer = Buffer.from(key.padEnd(32).slice(0, 32));
    const ivBuffer = Buffer.from(iv.padEnd(16).slice(0, 16));

    const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuffer, ivBuffer);
    let decrypted = decipher.update(data, 'base64', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
  }

  /**
   * RSA生成密钥对
   * @returns 包含公钥和私钥的对象
   */
  public static generateRSAKeyPair(): { publicKey: string; privateKey: string } {
    const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
      modulusLength: 2048,
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem'
      }
    });
    return { publicKey, privateKey };
  }

  /**
   * RSA公钥加密
   * @param data 待加密数据
   * @param publicKey 公钥
   * @returns 加密后的base64字符串
   */
  public static rsaEncrypt(data: string, publicKey: string): string {
    const encrypted = crypto.publicEncrypt(
      {
        key: publicKey,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256'
      },
      Buffer.from(data)
    );
    return encrypted.toString('base64');
  }

  /**
   * RSA私钥解密
   * @param data 待解密数据(base64格式)
   * @param privateKey 私钥
   * @returns 解密后的字符串
   */
  public static rsaDecrypt(data: string, privateKey: string): string {
    const decrypted = crypto.privateDecrypt(
      {
        key: privateKey,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256'
      },
      Buffer.from(data, 'base64')
    );
    return decrypted.toString();
  }

  /**
   * RSA签名
   * @param data 待签名数据
   * @param privateKey 私钥
   * @returns 签名后的base64字符串
   */
  public static rsaSign(data: string, privateKey: string): string {
    const sign = crypto.createSign('SHA256');
    sign.update(data);
    sign.end();
    return sign.sign(privateKey, 'base64');
  }

  /**
   * RSA验签
   * @param data 原始数据
   * @param signature 签名(base64格式)
   * @param publicKey 公钥
   * @returns 验签结果
   */
  public static rsaVerify(data: string, signature: string, publicKey: string): boolean {
    const verify = crypto.createVerify('SHA256');
    verify.update(data);
    verify.end();
    return verify.verify(publicKey, signature, 'base64');
  }

  /**
   * Base64编码
   * @param data 待编码数据
   * @returns 编码后的字符串
   */
  public static base64Encode(data: string): string {
    return Buffer.from(data).toString('base64');
  }

  /**
   * Base64解码
   * @param data 待解码数据
   * @returns 解码后的字符串
   */
  public static base64Decode(data: string): string {
    return Buffer.from(data, 'base64').toString();
  }

  /**
   * HMAC-SHA256签名
   * @param data 待签名数据
   * @param secret 密钥
   * @returns 签名后的十六进制字符串
   */
  public static hmacSha256(data: string, secret: string): string {
    return crypto.createHmac('sha256', secret).update(data).digest('hex');
  }

  /**
   * 生成随机字符串
   * @param length 长度
   * @returns 随机字符串
   */
  public static randomString(length: number): string {
    return crypto.randomBytes(Math.ceil(length / 2))
      .toString('hex')
      .slice(0, length);
  }

  /**
   * 生成指定范围的随机整数
   * @param min 最小值
   * @param max 最大值
   * @returns 随机整数
   */
  public static randomInt(min: number, max: number): number {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }

  /**
   * 生成UUID(v4)
   * @returns UUID字符串
   */
  public static generateUUID(): string {
    return crypto.randomUUID();
  }

  /**
   * 比较两个值是否相等，时间安全比较，防止时序攻击
   * @param a 值1
   * @param b 值2
   * @returns 是否相等
   */
  public static secureCompare(a: string, b: string): boolean {
    try {
      return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
    } catch (error) {
      // 长度不同时，timingSafeEqual会抛出错误
      return false;
    }
  }
} 